﻿module JsParserTests

open NUnit.Framework
open FParsec
open JsParser
open JsAst


[<TestFixture>]
type testJsParsing() =

    (* expects a valid parse and returns value *)
    member self.parse<'a> (parser:Parser<'a>) src : 'a =
        let result = run parser src 
        match result with
        | Success(result,_,_) -> result

    (* parses program source *)
    member self.parseJs src =
        let result = parseJs src 
        match result with
        | Success(result,_,_) -> result

    [<Test>]
    member self.testParseStringLiteral() =
        let result = self.parse expression """"hello" """
        let (StringLiteral("hello")) = result
        ()

    [<Test>]
    member self.testParseName() =
        let result = self.parse expression """x """
        let (Name("x")) = result
        ()

    [<Test>]
    member self.testParseOperatore() =
        let result = self.parse expression """x . y """
        let (PropertyExpression(Name("x"),"y")) = result
        ()

    [<Test>]
    member self.testParseCall() =
        let result = self.parse expression """x("hello")"""
        let (CallExpression(Name("x"),[(StringLiteral("hello"))])) = result
        ()

    [<Test>]
    member self.testNestedExpr() =
        let result = self.parse expression """x.y()"""
        let (CallExpression(PropertyExpression(Name("x"),"y"),[])) = result
        ()

    [<Test>]
    member self.testNew() =
        let result = self.parse expression """new x()"""
        let (NewExpression(Name("x"),[])) = result
        ()

    [<Test>]
    member self.testOpExpr() =
        let result = self.parse expression """2+3*4"""
        let (BinaryOperation("+",(NumberLiteral(2.0)),(BinaryOperation("*",(NumberLiteral(3.0)),(NumberLiteral(4.0)))))) = result
        ()

    [<Test>]
    member self.testFunctionExpression() =
        let result = self.parse expression """function(a){a}"""
        let (FunctionExpression(["a"],[(ExpressionStatement(Name("a")))])) = result
        ()

    [<Test>]
    member self.testStatements() =
        let stmts = self.parse statements """window.alert();b"""
        Assert.AreEqual(2, stmts.Length)
        let alert = stmts.[0]
        let (ExpressionStatement(CallExpression(PropertyExpression(Name("window"), "alert"), []))) = alert
        ()

    [<Test>]
    member self.testProgram() =
        let result = self.parseJs """
        /* two statements */
        window.alert();
        f();
        """
        Assert.AreEqual(2, result.Length)
        let alert = result.[0]
        let (ExpressionStatement(CallExpression(PropertyExpression(Name("window"), "alert"), []))) = alert
        ()